{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Dictionaries\n",
    "\n",
    "**Time**\n",
    "- Teaching: 15 min\n",
    "- Exercises: 10 min\n",
    "\n",
    "**Questions**:\n",
    "- \"How can I store more complicated data?\"\n",
    "- \"How can I retrieve complicated data efficiently?\"\n",
    "\n",
    "**Learning Objectives**:\n",
    "- \"Understand the fundamentals of a dictionary.\"\n",
    "- \"Understand advantages and disadvantages of a dictionary compared to a list.\"\n",
    "- \"Iterate through dictionaries.\"\n",
    "* * * * *"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## A python dictionary is a collection of key, value pairs. \n",
    "\n",
    "- The **key** is a way to name the data, and the **value** is the data itself. \n",
    "- Dictionaries are very powerful, especially when working with data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict = {\"name\": \"Forough Farrokhzad\", \\\n",
    "            \"year of birth\": 1935, \\\n",
    "            \"year of death\": 1967, \\\n",
    "            \"place of birth\": \"Iran\", \\\n",
    "            \"language\": \"Persian\"}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- The keys have to be **unique** and **immutable**. The usual suspects are strings and integers.\n",
    "- The values can be anything, including lists, and even other dictionaries"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict = {\"name\": \"Forough Farrokhzad\", \\\n",
    "            \"year of birth\": 1935, \\\n",
    "            \"year of death\": 1967, \\\n",
    "            \"place of birth\": \"Iran\", \\\n",
    "            \"language\": \"Persian\", \\\n",
    "            \"works\": [\"Remembrance of a Day\",\"Unison\",\"The Shower of Your Hair\",\"Portrait of Forough\"]}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This means that, although dictionaries can be values in other dictionaries, they cannot be keys."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "valid_dict = {'dict_nums':{1:'one', 2:'two', 3:'three'},\n",
    "             'dict_ints':{'one':1, 'two':2, 'three':3}}\n",
    "valid_dict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "invalid_dict = {{1:'one', 2:'two', 3:'three'}:'dict_nums',\n",
    "             {'one':1, 'two':2, 'three':3}:'dict_ints'}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- key/value pairs are **unordered**. Even though they print in a particular way, this doesn't mean that one comes before the other."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(poets_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Use dictionary keys to access the values\n",
    "\n",
    "- Instead of using indices to extract items, dictionaries uses key-value pairs to find and retrieve information."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(poets_dict.keys())\n",
    "print(poets_dict.values())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- If you wanted the value of a particular key:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict[\"name\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- Or perhaps you wanted the last element of the `works` list"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict[\"works\"][-1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dictionaries are different from lists\n",
    "\n",
    "In general, if you need data to be ordered or you have only simple data not needing to be subsetted, use a list.\n",
    "\n",
    "If the data is complex and hierarchical, the dictionary's `key` / `value` structure is very helpful. If you are only concerned about membership in a collection, dictionaries will always be much faster to reference, as the computer doesn't have to keep track of order. And of course, you can put a list (or even another dictionary!) inside a dictionary as the `value`."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Once a dictionary has been created, you can change the values of the data. \n",
    "\n",
    "This is because its a *mutable* object."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict[\"language\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict[\"language\"] = \"Farsi\"\n",
    "print(poets_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Remember, this means that if you assign this dictionary to a new variable, a change to either variable will change the dictionary."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_poets_dict = poets_dict\n",
    "\n",
    "poets_dict[\"language\"] = \"Persian\"\n",
    "print(\"new dict: \", new_poets_dict[\"language\"])\n",
    "\n",
    "new_poets_dict[\"language\"] = \"Farsi\"\n",
    "print(\"first dict: \", poets_dict[\"language\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## You can also add new keys to the dictionary.  \n",
    "\n",
    "- Note that dictionaries are \"indexed\" with square braces, just like lists--they look the same, even though they're very different."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict[\"gender\"] = \"Female\"\n",
    "print(poets_dict)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Dictionaries have their own methods.\n",
    "\n",
    "- We saw this above when we accessed the **keys** and **values**.\n",
    "- You can also get a list of keys *and* values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "poets_dict.items()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## You can loop through dictionaries\n",
    "\n",
    "- There are several ways to loop through dictionaries. Looping over `.keys()` is the most common.\n",
    "- Note the order is non-deterministic."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = {'apples': 0.49, 'oranges': 0.99, 'pears': 1.49, 'bananas': 0.32}\n",
    "\n",
    "for key in d.keys():\n",
    "    print(key, d[key])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* This makes it really easy to, say, change the value of items in the dictionary:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# add tax\n",
    "d = {'apples': 0.49, 'oranges': 0.99, 'pears': 1.49, 'bananas': 0.32}\n",
    "\n",
    "for key in d.keys():\n",
    "    d[key] = round(1.05 * d[key], 2)\n",
    "\n",
    "print(d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Challenge 1: Make your own\n",
    "\n",
    "Dictionaries can be nested, which means that dictionary keys can contain dictionaries themselves.\n",
    "\n",
    "1. Create two dictionaries, each representing one of your favorite musical artist. Each dictionary should have the following keys / value-type: `name`: (string) , `genre`: (string), `songs` (list), `age`: (integer)\n",
    "\n",
    "2. Create an outer dictionary called `musical_artists` that contain the two inner dictionaries."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Challenge 2: Compute the cost\n",
    "\n",
    "Using the dictionary below and a for loop, calculate how much it'll cost you to buy 2 pieces of each fruit."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "d = {'apples': 0.49, 'oranges': 0.99, 'pears': 1.49, 'bananas': 0.32}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Challenge 3: Check to see a key\n",
    "\n",
    "To see if something is in a container, use the `in` operator. This works for both lists and dictionaries:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "l = [\"Afghanistan\", \"Canada\", \"Sierra Leone\", \"Denmark\", \"Japan\"]\n",
    "d = {'apples': 0.49, 'oranges': 0.99, 'pears': 1.49, 'bananas': 0.32}\n",
    "\n",
    "print('Canada' in l)\n",
    "print('grapefruit' in d)\n",
    "print('grapefruit' not in d)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Below, I've given you a **list** containing 5 **dictionaries** representing some American states. \n",
    "\n",
    "1. Loop through all the dictionaries in the list\n",
    "2. Check to see if \"state bird\" is in the dictionary\n",
    "3. If the key is NOT in the dictionary, add the key and [assign](https://github.com/dlab-berkeley/python-intensive/blob/master/Glossary.md#assign) the value \"unknown\" to it"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "states = [{'state': 'Ohio', 'population': 11.6, 'year in union': 1803, 'state bird': 'Northern cardinal', 'capital': 'Columbus'},\n",
    "          {'state': 'Michigan', 'population': 9.9, 'year in union': 1837, 'capital': 'Lansing'},\n",
    "          {'state': 'California', 'population': 39.1, 'year in union': 1850, 'state bird': 'California quail', 'capital': 'Sacramento'},\n",
    "          {'state': 'Florida', 'population': 20.2, 'year in union': 1834, 'capital': 'Tallahassee'},\n",
    "          {'state': 'Alabama', 'population': 4.9, 'year in union': 1819, 'capital': 'Montgomery'}]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": true
   },
   "source": [
    "*****\n",
    "\n",
    "## Keypoints\n",
    "\n",
    "1. A python dictionary is a collection of key, value pairs.\n",
    "2. Use dictionary keys to access the values.\n",
    "3. Once a dictionary has been created, you can change the values of the data and assign new keys.\n",
    "4. Dictionaries have their own methods, and you can loop through key/value pairs.\n",
    "5. Dictionaries are different from lists in important ways."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.2"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": false,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
